#ifndef _MATH_VA_H_
#define _MATH_VA_H_

#include "./math_interpol.h"

namespace Mathematics {

	//! Aleatory samples
	/*!
		A namespace for containing a sort of aleatory variable generator
	*/
	namespace Sample{
		/*! defines the precision of the dRand() */
		const usint rand_range = 5000;
		//! Uniform(0,1)
		inline double dRand(){
			return ( rand() % rand_range ) / ((double)rand_range);
		};
		//! Sample of the Uniform(a,b)
		/*! 
			Commonly Uniform( 0.0, 1.0 )
			
			\param start lower bound
			\param end upper bound
			\return random value between start and end

			\code
			cout << Uniform() << endl	// prints a value between 0.0 and 1.0
			cout << Uniform(-1.0,3.75) << endl	// prints a value between -1.0 and 3.75
			\endcode
		*/
		inline double Uniform( const double &start = 0.0, const double &end = 1.0 ){
			return Interpolation::Linear( start, end, dRand() );
		};
		//! Sample of the Exponential(lambda)
		/*! 
			Commonly Exponential(1.0)
			
			\param lambda value of the parameter
			\return random positive value exponentially distributed
			
			\code
			cout << Exponential() << endl	// prints a sample of Exponential(1.0)
			cout << Exponential( 2.75 ) << endl	// prints a sample of Exponential(2.75)
			\endcode
		*/
		inline double Exponential( const double &lambda = 1.0 ){
			return -log( dRand() ) / lambda;
		};
		//! Sample of the Bernoulli(p)
		/*! 
			Commonly Bernoulli(0.5)
			
			\param probability value desired to success chance
			\return sample of the random variable ( 0.0 or 1.0 )
			
			\code
			cout << Bernoulli() << endl	// prints a sample of Bernoulli(0.5) (an even coin toss)
			cout << Bernoulli( 0.75 ) << endl	// prints a sample of Bernoulli(0.75)
			\endcode
		*/
		inline double Bernoulli( const double &probability = 0.5 ){
			return dRand() <= probability;
		};
		//! Sample of the Poisson(lambda,t)
		/*! 
			Commonly Poisson(0.5)
			
			\param lambda value desired to average
			\param t time of the sample
			\return sample of the random variable
			
			\code
			cout << Poisson() << endl	// prints a sample of Poisson(1.0,1.0)
			cout << Poisson( 2.0, 5.0 ) << endl	// prints a sample of Poisson(2.0,5.0)
			\endcode
		*/
		int Poisson( const double &lambda = 1.0, const double &t = 1.0 );
		/*! 
			Commonly Geometric(0.5)
			
			\param failure_probability value of the failure event probability
			\return sample of the random variable (number of tests until success)
			
			\code
			cout << Geometric() << endl			// prints a sample of Geometric(0.5) (even coin tosses until success)
			cout << Geometric( 0.8 ) << endl	// prints a sample of Geometric(0.8)
			\endcode
		*/
		inline int Geometric( const double &failure_probability = 0.5 ){
			return Upp( log( dRand() ) / log( failure_probability ) );
		};
		
		//! function for testing sample definitions
		void SampleTest();
	};

};

#endif
